package org.zero.concurrency.demo.example.publish;

import lombok.extern.slf4j.Slf4j;
import org.zero.concurrency.demo.annotations.NoRecommend;
import org.zero.concurrency.demo.annotations.NotThreadSafe;

/**
 * @program: concurrency-demo
 * @description: 对象逸出示例，在对象构造完成之前，不可以将其发布
 * @author: 01
 * @create: 2018-10-16 16:36
 **/
@Slf4j
@NotThreadSafe
@NoRecommend
public class Escape {

    private int thisCanBeEscape = 0;

    public Escape() {
        new InnerClass();
    }

    /**
     * 这个内部类的构造器里包含了对封装实例的隐含引用，这样在对象没有被正确构造完成之前就会被发布，由此导致不安全的因素在里面
     * 一个导致this引用在构造期间逸出的错误，它是在构造函数构造过程中启动了一个线程，无论是显式启动还是隐式启动，都会造成this引用的逸出
     * 新线程总会在所属对象构造完毕之前就已经看到它了，所以如果要在构造函数中创建线程，那么不要启动它，而是应该才用一个专有的start，或是其他的初始化的方式统一启动线程
     * 这里其实我们可以使用工厂方法和私有构造函数来完成对象创建和监听器的注册等等来避免不正确的发布
     */
    private class InnerClass {
        public InnerClass() {
            log.info("{}", Escape.this.thisCanBeEscape);
        }
    }

    public static void main(String[] args) {
        new Escape();
    }
}
